home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet internetowy / Rozne / HTTrack 3.40-2 / httrack-3.40-2.exe / {app} / src / mmsrip / main.c < prev    next >
C/C++ Source or Header  |  2006-01-23  |  23KB  |  754 lines

  1. /*
  2.  * $RCSfile: main.c,v $
  3.  * $Date: 2006/01/23 20:30:42 $ - $Revision: 1.32 $
  4.  *
  5.  * This file is distributed as a part of MMSRIP ( MMS Ripper ).
  6.  * Copyright (c) 2005-2006 Nicolas BENOIT
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify it
  9.  * under the terms of the GNU General Public License as published by the
  10.  * Free Software Foundation; either version 2, or (at your option) any
  11.  * later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  */
  23.  
  24.  
  25. #define _GNU_SOURCE
  26.  
  27. #include <stdlib.h>
  28. #include <stdio.h>
  29. #include <unistd.h>
  30. #include <string.h>
  31. #include <time.h>
  32. #include <sys/time.h>
  33. #include "common.h"
  34. #include "mms.h"
  35. #include "error.h"
  36.  
  37. #ifdef HAVE_GETOPT_H
  38. #include <getopt.h>
  39. #endif
  40.  
  41. /*
  42.  * options
  43.  */
  44. #if defined(SOLARIS) || defined(sun)
  45. static char * options = "ahvtqko:d:g:";
  46. #else
  47. static char * options = "-ahvtqko:d:g:";
  48. #endif
  49.  
  50. #ifdef HAVE_GETOPT_LONG
  51. static struct option long_options[] = {
  52.   {"about",   0, NULL, 'a'},
  53.   {"version", 0, NULL, 'v'},
  54.   {"help",    0, NULL, 'h'},
  55.   {"test",    0, NULL, 't'},
  56.   {"quiet",   0, NULL, 'q'},
  57.   {"trick",   0, NULL, 'k'},
  58.   {"output",  1, NULL, 'o'},
  59.   {"delay",   1, NULL, 'd'},
  60.   {"debug",   1, NULL, 'g'},
  61.   {NULL,      0, NULL,  0 }
  62. };
  63. #endif
  64.  
  65. /*
  66.  * usage
  67.  */
  68. void
  69. usage ( void )
  70. {
  71.   fprintf ( stderr, "%s (%s) version %s\n\n", PROGRAM_SHORT_NAME, PROGRAM_FULL_NAME, PROGRAM_VERSION );
  72.   fprintf ( stderr, "usage: %s <[-oFILE] stream url> ...\n\n", PROGRAM_SHORT_NAME );
  73.  
  74. #ifdef HAVE_GETOPT_LONG
  75.   fprintf ( stderr, "General Options:\n\t"                                                      \
  76.                     "-a, --about\t\tshow information about %s\n\t"                              \
  77.                     "-h, --help\t\tshow this help\n\t"                                          \
  78.                     "-v, --version\t\tshow version number\n\n"                                  \
  79.                     "Program Behaviour:\n\t"                                                    \
  80.                     "-oFILE, --output=FILE\toutput to specified file (can be repeated)\n\t"     \
  81.                     "-gFILE, --debug=FILE\toutput debug info to specified file\n\t"             \
  82.                     "-q, --quiet\t\tquiet mode (can be repeated)\n\t"                           \
  83.                     "-dDELAY, --delay=DELAY\tsave the stream during DELAY seconds and exit\n\t" \
  84.                     "-k, --trick\t\tattempt to trick recalcitrant servers\n\t"                  \
  85.                     "-t, --test\t\ttest mode (check stream availability)\n\n", PROGRAM_SHORT_NAME );
  86. #else
  87.   fprintf ( stderr, "General Options:\n\t"                                       \
  88.                     "-a\tshow information about %s\n\t"                          \
  89.                     "-h\tshow this help\n\t"                                     \
  90.                     "-v\tshow version number\n\n"                                \
  91.                     "Program Behaviour:\n\t"                                     \
  92.                     "-oFILE\toutput to specified file (can be repeated)\n\t"     \
  93.                     "-gFILE\toutput debug info to specified file\n\t"            \
  94.                     "-q\tquiet mode (can be repeated)\n\t"                       \
  95.                     "-dDELAY\tsave the stream during DELAY seconds and exit\n\t" \
  96.                     "-k\tattempt to trick recalcitrant servers\n\t"              \
  97.                     "-t\ttest mode (check stream availability)\n\n", PROGRAM_SHORT_NAME );
  98. #endif
  99.  
  100.   return;
  101. }
  102.  
  103.  
  104. /*
  105.  * main
  106.  */
  107. int
  108. main ( int argc,
  109.        char *argv[] )
  110. {
  111.   MMS *mms;
  112.   FILE *f;
  113.   FILE *stddebug = NULL;
  114.   char *output_filename;
  115.   STREAM_LIST *stream_list;
  116.   STREAM_LIST *block;
  117.   char c;
  118.   int ret = MMS_RET_SUCCESS;
  119.   int quiet = 0;
  120.   int trick = MMS_TRICK_DISABLED;
  121.   int retry = 0;
  122.   int test = 0;
  123.   int delay = 0;
  124.   time_t end = 0;
  125.   float speed = 0.0f;
  126.   struct timeval speed_last_update;
  127.   struct timeval now;
  128.   float elapsed_time;
  129.   ssize_t len_written;
  130.   uint64_t total_len_written = 0;
  131.   uint64_t old_total_len_written = 0;
  132.  
  133.   if ( ( stream_list = (STREAM_LIST *) malloc(sizeof(STREAM_LIST)) ) == NULL )
  134.     {
  135.       error ( "main", "early initialization failed" );
  136.       return 1;
  137.     }
  138.  
  139.   stream_list->next = NULL;
  140.   stream_list->stream = NULL;
  141.   stream_list->output = NULL;
  142.  
  143.   block = stream_list;
  144.  
  145. #ifdef HAVE_GETOPT_LONG
  146.   while ( ( c = getopt_long(argc, argv, options, long_options, NULL) ) != -1 )
  147. #elif defined(SOLARIS) || defined(sun)
  148.   /* Implementation of getopt in Solaris is a bit strange, it returns -1 even if there are still args to parse... */
  149.   while ( optind < argc )
  150. #else
  151.   while ( ( c = getopt(argc, argv, options) ) != -1 )
  152. #endif
  153.     {
  154. #if defined(SOLARIS) || defined(sun)
  155.       c = getopt ( argc, argv, options );
  156. #endif
  157.       switch (c)
  158.         {
  159.         case 'h':
  160.           {
  161.             fprintf ( stderr, "\n" );
  162.             usage();
  163.             return 0;
  164.           }
  165.  
  166.         case 'v':
  167.           {
  168.             fprintf ( stderr, "%s version %s\n", PROGRAM_SHORT_NAME, PROGRAM_VERSION);
  169.             return 0;
  170.           }
  171.  
  172.         case 'a':
  173.           {
  174.             fprintf ( stderr, "\n" );
  175.             fprintf ( stderr, "%s (%s) version %s\n\n", PROGRAM_SHORT_NAME, PROGRAM_FULL_NAME, PROGRAM_VERSION);
  176.             fprintf ( stderr, "Written by %s.\n", PROGRAM_AUTHORS );
  177.             fprintf ( stderr, "With a lot of help from %s.\n\n", PROGRAM_HELPERS );
  178.             fprintf ( stderr, "This program is free software; you can redistribute it and/or\nmodify it under the terms "         \
  179.                               "of the GNU General Public License\nas published by the Free Software Foundation; either version 2" \
  180.                               ",\nor (at your option) any later version.\n\n" );
  181.             return 0;
  182.           }
  183.  
  184.         case 't':
  185.           {
  186.             test = 1;
  187.             break;
  188.           }
  189.  
  190.         case 'q':
  191.           {
  192.             quiet += 1;
  193.             break;
  194.           }
  195.  
  196.         case 'k':
  197.           {
  198.             trick = MMS_TRICK_ENABLED;
  199.             break;
  200.           }
  201.  
  202.         case 'o':
  203.           {
  204.             if ( optarg != NULL )
  205.               {
  206.                 if ( block->stream != NULL )
  207.                   {
  208.                     if ( ( block->next = malloc ( sizeof(STREAM_LIST) ) ) == NULL )
  209.                       {
  210.                         error ( "main", "early initialization failed" );
  211.                         ret = MMS_RET_ERROR;
  212.                         goto clean;
  213.                       }
  214.  
  215.                     block = block->next;
  216.                     block->next = NULL;
  217.                     block->stream = NULL;
  218.                   }
  219.  
  220.                 if ( block->output != NULL )
  221.                   free ( block->output );
  222.  
  223.                 block->output = (char *) strdup ( optarg );
  224.               }
  225.  
  226.             break;
  227.           }
  228.  
  229.         case 'g':
  230.           {
  231.             if ( optarg != NULL )
  232.               {
  233.                 if ( stddebug != NULL )
  234.                   fclose ( stddebug );
  235.  
  236.                 if ( ( stddebug = fopen ( optarg, "w" ) ) == NULL )
  237.                   {
  238.                     if ( quiet < 2 )
  239. #ifdef HAVE_VSNPRINTF
  240.                       warning ( NULL, "unable to write debug info in \'%s\'", optarg );
  241. #else
  242.                       warning ( NULL, "unable to write debug info in specified file" );
  243. #endif
  244.                   }
  245.                 else
  246.                   {
  247.                     fprintf ( stddebug, "%s (%s) version %s\n\n", PROGRAM_SHORT_NAME, PROGRAM_FULL_NAME, PROGRAM_VERSION);
  248.                     fprintf ( stddebug, "--> debug log begins now\n" );
  249.                   }
  250.               }
  251.  
  252.             break;
  253.           }
  254.  
  255.         case 'd':
  256.           {
  257.             if ( optarg != NULL )
  258.               {
  259.                 delay = atoi( optarg );
  260.  
  261.                 if ( delay < 0 )
  262.                   delay = 0;
  263.               }
  264.  
  265.             break;
  266.           }
  267.  
  268.  
  269. #if defined(SOLARIS) || defined(sun)
  270.         case -1:
  271.           {
  272.             if ( optind >= argc )
  273.               break;
  274. #else
  275.         case 1:
  276.           {
  277.             if ( optarg != NULL )
  278.               {
  279. #endif
  280.                 if ( block->stream != NULL )
  281.                   {
  282.                     if ( ( block->next = malloc ( sizeof(STREAM_LIST) ) ) == NULL )
  283.                       {
  284.                         error ( "main", "early initialization failed" );
  285.                         ret = MMS_RET_ERROR;
  286.                         goto clean;
  287.                       }
  288.  
  289.                     block = block->next;
  290.                     block->next = NULL;
  291.                     block->output = NULL;
  292.                   }
  293. #if defined(SOLARIS) || defined(sun)
  294.                 /* optind is not incremented when meeting something else than an option, so we do that... */
  295.                 block->stream = (char *) strdup ( argv[optind++] );
  296. #else
  297.                 block->stream = (char *) strdup ( optarg );
  298.               }
  299. #endif
  300.             break;
  301.           }
  302.         }
  303.     }
  304.  
  305.   if ( stream_list->stream == NULL )
  306.     {
  307.       usage ( );
  308.       ret = MMS_RET_ERROR;
  309.       goto clean;
  310.     }
  311.  
  312.   if ( !quiet )
  313.     {
  314.       fprintf ( stderr, "\n" );
  315.       fprintf ( stderr, "%s (%s) version %s\n\n", PROGRAM_SHORT_NAME, PROGRAM_FULL_NAME, PROGRAM_VERSION );
  316.     }
  317.  
  318.   for ( block=stream_list; block!=NULL; block=(STREAM_LIST*)block->next )
  319.     {
  320.       if ( block->stream == NULL )
  321.         {
  322.           if ( quiet < 2 )
  323.             {
  324.               if ( block->output == NULL )
  325. #ifdef HAVE_VSNPRINTF
  326.                 error ( "main", "invalid invocation of %s", PROGRAM_SHORT_NAME );
  327. #else
  328.                 error ( "main", "invalid invocation of mmsrip" );
  329. #endif
  330.               else
  331. #ifdef HAVE_VSNPRINTF
  332.                 error ( "main", "output to \'%s\' is not attached to any stream", block->output );
  333. #else
  334.                 error ( "main", "one of the -o output is not attached to any stream" );
  335. #endif
  336.             }
  337.  
  338.           ret = MMS_RET_ERROR;
  339.           goto clean;
  340.         }
  341.  
  342.       if ( block->output == NULL )
  343.         {
  344.           char *tmp = strchr ( block->stream, '/' );
  345.           char *interro_ptr = strchr ( block->stream, '?' );
  346.  
  347.           if ( interro_ptr == NULL )
  348.             output_filename = strrchr ( block->stream, '/' );
  349.           else
  350.             {
  351.               do  /* we look for the last '/' before the first '?' */
  352.                 {
  353.                   output_filename = tmp;
  354.                   tmp = strchr ( tmp+1, '/' );
  355.                 }
  356.               while ( ( tmp < interro_ptr ) && ( tmp != NULL ) );
  357.             }
  358.  
  359.           if ( output_filename == NULL )
  360.             {
  361.               if ( quiet < 2 )
  362. #ifdef HAVE_VSNPRINTF
  363.                 error ( "main", "malformed url: \'%s\'", block->stream );
  364. #else
  365.                 error ( "main", "malformed url" );
  366. #endif
  367.  
  368.               ret = MMS_RET_ERROR;
  369.               continue;
  370.             }
  371.  
  372.           ++output_filename;
  373.  
  374.           if ( strlen ( output_filename ) == 0 )
  375.             {
  376.               if ( quiet < 2 )
  377. #ifdef HAVE_VSNPRINTF
  378.                 error ( "main", "malformed url: \'%s\'", block->stream );
  379. #else
  380.                 error ( "main", "malformed url" );
  381. #endif
  382.  
  383.               ret = MMS_RET_ERROR;
  384.               continue;
  385.             }
  386.  
  387.           block->output = (char *) strdup ( output_filename );
  388.  
  389.           /* we clean filenames that look like 'stream.asf?digest=7Q2bjXo&provider=lala' */
  390.           if ( ( interro_ptr = strchr(block->output,'?') ) != NULL )
  391.             *interro_ptr = '\0';
  392.         }
  393.     }
  394.  
  395.   if ( ret != MMS_RET_SUCCESS )
  396.     goto clean;
  397.  
  398.   if ( delay != 0 )
  399.     end = time(NULL) + delay;
  400.  
  401.   for ( block=stream_list; block!=NULL; block=(STREAM_LIST*)(retry?block:block->next) )
  402.     {
  403.       output_filename = block->output;
  404.       retry = 0;
  405.  
  406.       if ( !test )
  407.         {
  408.           if ( ( f = fopen ( output_filename, "w" ) ) == NULL )
  409.             {
  410.               if ( quiet < 2 )
  411. #ifdef HAVE_VSNPRINTF
  412.                 error ( "main", "unable to write in \'%s\'", output_filename );
  413. #else
  414.                 error ( "main", "unable to write in output file" );
  415. #endif
  416.  
  417.               ret = MMS_RET_ERROR;
  418.               continue;
  419.             }
  420.         }
  421.       else
  422.         f = NULL;
  423.  
  424.       if ( ( mms = mms_create ( block->stream, f, stddebug, trick, test?1:(quiet>>1) ) ) == NULL )
  425.         {
  426.           if ( quiet < 2 )
  427.             error ( "main", "unable to create mms struct" );
  428.  
  429.           if ( !test )
  430.             {
  431.               fclose ( f );
  432.               remove ( output_filename );
  433.             }
  434.  
  435.           ret = MMS_RET_ERROR;
  436.           continue;
  437.         }
  438.  
  439.       if ( !quiet )
  440.         fprintf ( stderr, "Connecting ...\r" );
  441.  
  442.       if ( mms_connect ( mms ) != MMS_RET_SUCCESS )
  443.         {
  444.           if ( quiet < 2 )
  445.             error ( "main", "unable to connect" );
  446.  
  447.           mms_destroy ( mms );
  448.  
  449.           if ( !test )
  450.             {
  451.               fclose ( f );
  452.               remove ( output_filename );
  453.             }
  454.  
  455.           ret = MMS_RET_ERROR;
  456.           continue;
  457.         }
  458.  
  459.       if ( !quiet )
  460.         fprintf ( stderr, "Handshaking ...\r" );
  461.  
  462.       if ( mms_handshake ( mms ) != MMS_RET_SUCCESS )
  463.         {
  464.           if ( ( quiet < 2 ) && ( !test ) )
  465.             error ( "main", "unable to handshake" );
  466.  
  467.           mms_disconnect ( mms );
  468.           mms_destroy ( mms );
  469.  
  470.           if ( !test )
  471.             {
  472.               fclose ( f );
  473.               remove ( output_filename );
  474.             }
  475.  
  476.           if ( !quiet )
  477.             {
  478.               if ( !test )
  479.                 fprintf ( stderr, "Stream \'%s\' is not good.\n\n", block->stream );
  480.               else
  481.                 fprintf ( stderr, "Stream \'%s\' is not good.\n", block->stream );
  482.             }
  483.  
  484.           ret = MMS_RET_ERROR;
  485.           continue;
  486.         }
  487.  
  488.       if ( test )
  489.         {
  490.           if ( !quiet )
  491.             fprintf ( stderr, "Stream \'%s\' is available.\n", block->stream );
  492.  
  493.           mms_disconnect ( mms );
  494.           mms_destroy ( mms );
  495.           continue;
  496.         }
  497.  
  498.       if ( !quiet )
  499.         fprintf ( stderr, "Getting header ...\r" );
  500.  
  501.       if ( ( len_written = mms_write_stream_header ( mms ) ) == MMS_RET_ERROR )
  502.         {
  503.           if ( quiet < 2 )
  504.             error ( "main", "unable to write stream header" );
  505.  
  506.           mms_disconnect ( mms );
  507.           mms_destroy ( mms );
  508.           fclose ( f );
  509.           remove ( output_filename );
  510.           ret = MMS_RET_ERROR;
  511.           continue;
  512.         }
  513.  
  514.       total_len_written = len_written;
  515.  
  516.       if ( !quiet )
  517.         fprintf ( stderr, "Rip is about to start ...\r" );
  518.  
  519.       if ( mms_begin_rip ( mms ) != MMS_RET_SUCCESS )
  520.         {
  521.           if ( quiet < 2 )
  522.             error ( "main", "unable to begin the rip" );
  523.  
  524.           mms_disconnect ( mms );
  525.           mms_destroy ( mms );
  526.           fclose ( f );
  527.           remove ( output_filename );
  528.           ret = -1;
  529.           continue;
  530.         }
  531.  
  532.       if ( mms->is_live == MMS_LIVE )
  533.         {
  534.           if ( !quiet )
  535.             {
  536.               
  537.               fprintf ( stderr, "                                                            \r" );
  538.               fprintf ( stderr, "%s: %d bytes written (--.- kbps)\r", output_filename, (ssize_t)total_len_written );
  539.               gettimeofday ( &speed_last_update, NULL );
  540.             }
  541.  
  542.           while ( 1 )
  543.             {
  544.               len_written = mms_write_stream_data ( mms );
  545.  
  546.               if ( len_written == 0 )
  547.                 break;
  548.               else if ( len_written == MMS_RET_ERROR )
  549.                 {
  550.                   if ( quiet < 2 )
  551.                     error ( "main", "unable to write stream data" );
  552.  
  553.                   ret = MMS_RET_ERROR;
  554.                   break;
  555.                 }
  556.               else if ( len_written == MMS_RET_NO_AUTH )
  557.                 {
  558.                   if ( trick == MMS_TRICK_DISABLED )
  559.                     {
  560.                       /* we retry with the trick enabled */
  561.                       if ( quiet < 2 )
  562.                         fprintf ( stderr, "\r*** retrying with the anti-recalcitrant servers trick enabled ***\n" );
  563.  
  564.                       trick = MMS_TRICK_ENABLED;
  565.                       retry = 1;
  566.                     }
  567.                   else
  568.                     {
  569.                       /* it's definitely not working */
  570.                       if ( quiet < 2 )
  571.                         error ( "main", "unable to write stream data" );
  572.  
  573.                       ret = MMS_RET_NO_AUTH;
  574.                     }
  575.  
  576.                   break;
  577.                 }
  578.  
  579.               total_len_written += len_written;
  580.  
  581.               if ( !quiet )
  582.                 {
  583.                   gettimeofday ( &now, NULL );
  584.  
  585.                   if ( now.tv_sec > speed_last_update.tv_sec )
  586.                     {
  587.                       elapsed_time = (now.tv_sec - speed_last_update.tv_sec) + ((now.tv_usec - speed_last_update.tv_usec) / 1000000.0f);
  588.  
  589.                       if ( elapsed_time >= 1.0f )
  590.                         {
  591.                           speed = ( ( ((float) (total_len_written-old_total_len_written)) / elapsed_time) / 1024.0f );
  592.                           old_total_len_written = total_len_written;
  593.                           gettimeofday ( &speed_last_update, NULL );
  594.                         }
  595.                     }
  596.  
  597.                   if ( speed > 0.0f )
  598.                     {
  599.                       if ( (speed / 1024.0f) >= 1.0f )
  600.                         fprintf ( stderr, "%s: %d bytes written (%.1f mbps)    \r", output_filename, (ssize_t)total_len_written, speed/1024.0f );
  601.                       else
  602.                         fprintf ( stderr, "%s: %d bytes written (%.1f kbps)    \r", output_filename, (ssize_t)total_len_written, speed );
  603.                     }
  604.                   else
  605.                     fprintf ( stderr, "%s: %d bytes written (--.- kbps)    \r", output_filename, (ssize_t)total_len_written );
  606.                 }
  607.  
  608.               fflush ( f );
  609.  
  610.               if ( delay != 0 )
  611.                 {
  612.                   if ( end <= time(NULL) )
  613.                     {
  614.                       delay = -1;
  615.                       break;
  616.                     }
  617.                 }
  618.             }
  619.  
  620.           /* for a live, we should rewrite the header */
  621.  
  622.           if ( ( ret == MMS_RET_SUCCESS ) && ( !quiet ) && ( !retry ) )
  623.             fprintf ( stderr, "%s: %d bytes written              \r", output_filename, (ssize_t)total_len_written );
  624.         }
  625.       else
  626.         {
  627.           register const double coef = 100.0 / (double) mms->expected_file_size;
  628.  
  629.           if ( !quiet )
  630.             {
  631.               fprintf ( stderr, "                                                            \r" );
  632.               fprintf ( stderr, "%s: %.2f%% (--.- kbps)\r", output_filename, (double) total_len_written * coef );
  633.               gettimeofday ( &speed_last_update, NULL );
  634.             }
  635.  
  636.           while ( 1 )
  637.             {
  638.               len_written = mms_write_stream_data ( mms );
  639.  
  640.               if ( len_written == 0 )
  641.                 break;
  642.               else if ( len_written == MMS_RET_ERROR )
  643.                 {
  644.                   if ( quiet < 2 )
  645.                     error ( "main", "unable to write stream data" );
  646.  
  647.                   ret = MMS_RET_ERROR;
  648.                   break;
  649.                 }
  650.               else if ( len_written == MMS_RET_NO_AUTH )
  651.                 {
  652.                   if ( trick == MMS_TRICK_DISABLED )
  653.                     {
  654.                       /* we retry with the trick enabled */
  655.                       if ( quiet < 2 )
  656.                         fprintf ( stderr, "\r*** retrying with the anti-recalcitrant servers trick enabled ***\n" );
  657.  
  658.                       trick = MMS_TRICK_ENABLED;
  659.                       retry = 1;
  660.                     }
  661.                   else
  662.                     {
  663.                       /* it's definitely not working */
  664.                       if ( quiet < 2 )
  665.                         error ( "main", "unable to write stream data" );
  666.  
  667.                       ret = MMS_RET_NO_AUTH;
  668.                     }
  669.  
  670.                   break;
  671.                 }
  672.  
  673.               total_len_written += len_written;
  674.  
  675.               if ( !quiet )
  676.                 {
  677.                   gettimeofday ( &now, NULL );
  678.  
  679.                   if ( now.tv_sec > speed_last_update.tv_sec )
  680.                     {
  681.                       elapsed_time = (now.tv_sec - speed_last_update.tv_sec) + ((now.tv_usec - speed_last_update.tv_usec) / 1000000.0f);
  682.  
  683.                       if ( elapsed_time >= 1.0f )
  684.                         {
  685.                           speed = ( ( ((float) (total_len_written-old_total_len_written)) / elapsed_time) / 1024.0f );
  686.                           old_total_len_written = total_len_written;
  687.                           gettimeofday ( &speed_last_update, NULL );
  688.                         }
  689.                     }
  690.  
  691.                   if ( speed > 0.0f )
  692.                     {
  693.                       if ( (speed / 1024.0f) >= 1.0f )
  694.                         fprintf ( stderr, "%s: %.2f%% (%.1f mbps)    \r", output_filename, (double) total_len_written * coef, speed/1024.0f );
  695.                       else
  696.                         fprintf ( stderr, "%s: %.2f%% (%.1f kbps)    \r", output_filename, (double) total_len_written * coef, speed );
  697.                     }
  698.                   else
  699.                     fprintf ( stderr, "%s: %.2f%% (--.- kbps)    \r", output_filename, (double) total_len_written * coef );
  700.                 }
  701.  
  702.               fflush ( f );
  703.  
  704.               if ( delay != 0 )
  705.                 {
  706.                   if ( end <= time(NULL) )
  707.                     {
  708.                       delay = -1;
  709.                       break;
  710.                     }
  711.                 }
  712.             }
  713.  
  714.           if ( ( ret == MMS_RET_SUCCESS ) && ( !quiet ) && ( delay != -1 ) && ( !retry ) )
  715.             fprintf ( stderr, "%s: 100.00%%                 \r", output_filename );
  716.         }
  717.  
  718.       mms_disconnect ( mms );
  719.       mms_destroy ( mms );
  720.  
  721.       fclose ( f );
  722.  
  723.       if ( delay == -1 )
  724.         break;
  725.     }
  726.  
  727.  clean:
  728.   if ( !quiet )
  729.     fprintf ( stderr, "\n" );
  730.  
  731.   if ( stddebug != NULL )
  732.     {
  733.       fprintf ( stddebug, "\n\n--> debug log ends now\n" );
  734.       fclose ( stddebug );
  735.     }
  736.  
  737.   for ( block=stream_list; block!=NULL; )
  738.     {
  739.       STREAM_LIST *old;
  740.       old = block;
  741.       block = (STREAM_LIST *) block->next;
  742.  
  743.       if ( old->stream != NULL )
  744.         free ( old->stream );
  745.  
  746.       if ( old->output != NULL )
  747.         free ( old->output );
  748.  
  749.       free ( old );
  750.     }
  751.  
  752.   return (ret<0) ? (ret*-1) : ret;
  753. }
  754.